/*
 * DIM-SUM操作系统 -- ioremap实现文件
 *
 * Copyright (C) 2023 国科础石(重庆)软件有限公司
 *
 * 作者: Dong Peng <w-pengdong@kernelsoft.com>
 *
 * License terms: GNU General Public License (GPL) version 3
 *
 */

#include <dim-sum/bug.h>
#include <dim-sum/cache.h>
#include <dim-sum/ioremap.h>
#include <dim-sum/mm_types.h>
#include <dim-sum/mmu.h>
#include <dim-sum/virt_space.h>

#include <asm/memory.h>
#include <asm/io.h>

#include <dim-sum/mm.h>

void vunmap(const void *addr)
{
	/* TO-DO */
}

void iounmap(void __iomem *addr)
{
	/* TO-DO */
}

int arch_ioremap_range(unsigned long addr,
		unsigned long end, phys_addr_t phys_addr, page_attr_t prot)
{
	int ret = 0;

	BUG_ON(addr >= end);
	ret = arch_mmu_ioremap_range(addr, end, phys_addr, (unsigned long)prot);
	if (ret)
		return ret;
	flush_cache_vmap(addr, end);

	return ret;
}

void __iomem *__ioremap(phys_addr_t phys_addr, size_t size, page_attr_t prot)
{
	unsigned long last_addr;
	unsigned long offset = phys_addr & ~PAGE_MASK;
	int err;
	unsigned long addr;
	struct vm_struct *area;

	size = PAGE_ALIGN(size + offset);
	last_addr = phys_addr + size - 1;
	if (!size || last_addr < phys_addr || (last_addr & ~PHYS_MASK))
		return NULL;
	/*
	 * 不能映射正常的RAM
	 */
	if (pgnum_is_valid(__phys_to_pgnum(phys_addr))) {
		BUG();
		return NULL;
	}

	area = get_virt_space(VIRT_SPACE_IOREMAP, size, 0x200000, 0);
	if (!area)
		return NULL;
	addr = (unsigned long)area->addr;
	area->phys_addr = phys_addr;

	if (phys_addr >= 0x9c0000000 && phys_addr <= 0x9cfffffff)
		printk("%s : phys = %llx, addr = %llx, end = %llx, prot = %x\n", __func__, phys_addr, addr, addr + size, prot);

	err = arch_ioremap_range(addr, addr + size, phys_addr, prot);
	if (err) {
		BUG();
		vunmap((void *)addr);
		return NULL;
	}

	return (void __iomem *)(offset + addr);
}
